import { STORE_KEYS } from '@/configs/store.config';
import { Game, RoundInfo } from '@/types/game';
import { useLocalStorageState } from 'ahooks';
import { ceil, cloneDeep, floor, remove } from 'lodash';
import { nanoid } from 'nanoid';
import { useCallback, useMemo } from 'react';
import dayjs from 'dayjs';
import {
  getGamePersonIds,
  getGameResultScores,
  getGameTotalPoints,
} from '@/funcs/game';

export function useGameStore() {
  const [game, setGame] = useLocalStorageState<Game>(STORE_KEYS.GAME_STORE, {
    defaultValue: {
      roundInfos: [],
      eastPerson: undefined,
      southPerson: undefined,
      westPerson: undefined,
      northPerson: undefined,
      startTime: undefined,
      endTime: undefined,
    } as Game,
  });

  /** 设置参赛人员 */
  const setGamePerson = useCallback(
    function (position: string, personId: string) {
      if (position) {
        setGame({ ...game, [position]: personId });
      }
    },
    [game, setGame],
  );

  /** 依照东南西北的顺序获取参赛选手的姓名数组 */
  const getPositionPersonIds = useCallback(
    function () {
      return getGamePersonIds(game);
    },
    [game],
  );

  /** 通过roundId获取一个roundInfo */
  const getRoundInfoById = useCallback(
    function (roundId: string) {
      return game.roundInfos.find(r => r.roundId === roundId);
    },
    [game],
  );

  /** 创建一个新的roundInfo数据 */
  const createRoundInfo = useCallback(function (): RoundInfo {
    return {
      roundId: nanoid(),
      courtNum: undefined,
      huMethod: undefined,
      huPersonId: '',
      multiple: undefined,
      reachPersonIds: [],
      roundResult: undefined,
      scene: undefined,
      sceneNum: undefined,
      signNum: undefined,
      tingPersonIds: [],
      triggerPersonId: '',
      changePoints: [],
    };
  }, []);

  /**
   * 获取两个局信息的先后顺序
   * @returns 负数表示第一个在前，相等表示位置信息相同
   */
  const getTwoRoundsOrder = useCallback(
    (oneRound: RoundInfo, anotherRound: RoundInfo) => {
      const sceneOrders = { 东: 0, 南: 1, 西: 2, 北: 3 };
      const oneSceneOrder = sceneOrders[oneRound.scene!];
      const anotherSceneOrder = sceneOrders[anotherRound.scene!];
      if (oneSceneOrder === anotherSceneOrder) {
        // 继续判断
        // 局数相等
        if (oneRound.sceneNum === anotherRound.sceneNum) {
          // 判断场数
          if (oneRound.courtNum === anotherRound.courtNum) {
            return -1;
          } else {
            return oneRound.courtNum! - anotherRound.courtNum!;
          }
        } else {
          return oneRound.sceneNum! - anotherRound.sceneNum!;
        }
      } else {
        // 返回顺序比较值
        return oneSceneOrder - anotherSceneOrder;
      }
    },
    [],
  );

  /** 获取一局数据应当插入的位置 */
  const getRoundInsertIndex = useCallback(
    (roundInfo: RoundInfo) => {
      const roundInfos = game.roundInfos;
      for (let i = 0; i < roundInfos.length; i++) {
        const r = roundInfos[i];
        // 获取正数时，表示传入的信息应插在这个信息的前面
        const order = getTwoRoundsOrder(r, roundInfo);
        if (order > 0) {
          return i;
        }
      }
      return roundInfos.length;
    },
    [game, getTwoRoundsOrder],
  );

  /** 添加一个roundInfo数据 */
  const pushRoundInfo = useCallback(
    (roundInfo: RoundInfo) => {
      const gameTemp = cloneDeep(game);
      const insertIndex = getRoundInsertIndex(roundInfo);
      gameTemp.roundInfos.splice(insertIndex, 0, roundInfo);
      setGame(gameTemp);
    },
    [game, setGame, getRoundInsertIndex],
  );

  /** 编辑保存一个roundInfo数据 */
  const saveRoundInfo = useCallback(
    (roundInfo: RoundInfo) => {
      const gameTemp = cloneDeep(game);
      const findIndex = game.roundInfos.findIndex(
        r => r.roundId === roundInfo.roundId,
      );
      if (findIndex === -1) return;
      gameTemp.roundInfos.splice(findIndex, 1, roundInfo);
      setGame(gameTemp);
    },
    [game, setGame],
  );

  /** 删除一局信息 */
  const removeRound = useCallback(
    (roundId: string) => {
      const gameTemp = cloneDeep(game);
      remove(gameTemp.roundInfos, r => r.roundId === roundId);
      setGame(gameTemp);
    },
    [game, setGame],
  );

  /** 获取局数信息 */
  const getRoundInfos = useCallback(
    function () {
      return game.roundInfos || [];
    },
    [game],
  );

  /** 计算最终得点 */
  const computeTotalPoints = useCallback(() => {
    return getGameTotalPoints(game);
  }, [game]);

  /** 获取最终结算分数 */
  const getGameCloseResult = useCallback(() => {
    return getGameResultScores(game);
  }, [game]);

  /** 重置存储数据并将该局数据返回 */
  const clearGame = useCallback(() => {
    setGame({
      roundInfos: [],
      eastPerson: undefined,
      northPerson: undefined,
      southPerson: undefined,
      westPerson: undefined,
      startTime: undefined,
      endTime: undefined,
    });

    game.endTime = game.endTime || dayjs().format('YYYY-MM-DD HH:mm:ss');

    return game;
  }, [game, setGame]);

  /** 设置开始时间 */
  const setStartTime = useCallback(() => {
    const gameTemp = cloneDeep(game);
    gameTemp.startTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
    setGame(gameTemp);
  }, [game, setGame]);

  /** 比赛是否已经开始 */
  const isGameStart = useMemo(() => !!game.startTime, [game]);

  /** 比赛是否为历史比赛，true表示为历史比赛 */
  const isHistoryGame = useMemo(() => !!game.endTime, [game]);

  /** 设置一个game */
  const setHistoryGame = useCallback(
    (historyGame: Game) => {
      setGame(historyGame);
      if (isGameStart && !isHistoryGame) {
        return game;
      }
    },
    [game, isGameStart, setGame, isHistoryGame],
  );

  return {
    setGamePerson,
    getPositionPersonIds,
    getRoundInfoById,
    createRoundInfo,
    pushRoundInfo,
    saveRoundInfo,
    removeRound,
    getRoundInfos,
    computeTotalPoints,
    getGameCloseResult,
    clearGame,
    setStartTime,
    isGameStart,
    isHistoryGame,
    setHistoryGame,
    setGame,
  };
}
